﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mani.Common.WorkflowEngine;
using Mani.Common;

namespace RastinArgham.CRM.Business
{
    public class ServiceOrderWorkflow : WorkflowBasic
    {
        public override Guid TypeId
        {
            get { return new Guid("974e5622-200a-4d26-b1f9-e8b0c75e41a9"); }
        }

        protected override void InitializeStateManager()
        {
            // StateIds here are also hardcoded in Order.cs model
            // When Adding/Deleting/Changing State Ids here, note to change them in those other places!
            // p.s Adding required actions in database


            WorkflowState stInitial = base.StateEngine.CreateState(1, "وضعیت اولیه");
            WorkflowState stOnlineRegister = base.StateEngine.CreateState(5, "ثبت نام اینترنتی");
            WorkflowState stRegister = base.StateEngine.CreateState(10, "ثبت نام مشترک");
            WorkflowState stCallCustomer = base.StateEngine.CreateState(20, "تماس با مشترک");
            WorkflowState stSendModem = base.StateEngine.CreateState(30, "ارسال مودم");
            WorkflowState stRecieveMoneyAndInstallModem = base.StateEngine.CreateState(40, "دریافت نقدی و نصب");
            WorkflowState stCompleteRegistrationForm = base.StateEngine.CreateState(60, "تکمیل فرم ثبت نام");
            WorkflowState stConfirmDocuments = base.StateEngine.CreateState(70, "تایید مدارک");
            WorkflowState stArchiveDocuments = base.StateEngine.CreateState(80, "آرشیو مدارک");
            WorkflowState stControlDocuments = base.StateEngine.CreateState(85, "کنترل مدارک");
            WorkflowState stRegisterInSaleSoftware = base.StateEngine.CreateState(87, "ثبت نام مبین");
            WorkflowState stRegisterFailed = base.StateEngine.CreateState(88, "ثبت نام ناموفق");
            WorkflowState stConfirmFinancial = base.StateEngine.CreateState(90, "تایید مالی");
            WorkflowState stActivateService = base.StateEngine.CreateState(100, "فعال سازی مبین");

            WorkflowState stActivateServiceFailed = base.StateEngine.CreateState(102, "فعال سازی ناموفق");
            WorkflowState stFinalizeActivation = base.StateEngine.CreateState(104, "تکمیل فرم ثبت نام");
            WorkflowState stFinalizeActivationFailed = base.StateEngine.CreateState(106, "تکمیل فرم ثبت نام ناموفق");

            WorkflowState stInUse = base.StateEngine.CreateState(110, "سرویس فعال");
            WorkflowState stCancel = base.StateEngine.CreateState(120, "انصراف");
            WorkflowState stServiceFinished = base.StateEngine.CreateState(130, "پایان سرویس");


            // Transitions 
            stInitial.AddNewTransition("sys_event_1", stOnlineRegister, null, null);
            stInitial.AddNewTransition("sys_event_2", stRegister, null, null);

            stOnlineRegister.AddNewTransition("تایید سفارش", stCallCustomer, null, null);
            stOnlineRegister.AddNewTransition("انصراف", stCancel, new WorkflowGuard(CheckCancelationReason), null);

            stRegister.AddNewTransition("تایید سفارش", stCallCustomer, null, null);
            stRegister.AddNewTransition("انصراف", stCancel, new WorkflowGuard(CheckCancelationReason), null);

            stCallCustomer.AddNewTransition("تماس گرفته شد", stSendModem, null, null);
            stCallCustomer.AddNewTransition("انصراف", stCancel, new WorkflowGuard(CheckCancelationReason), null);

            stSendModem.AddNewTransition("مودم ارسال شد", stRecieveMoneyAndInstallModem, new WorkflowGuard(CheckUsername), null);
            stSendModem.AddNewTransition("انصراف", stCancel, new WorkflowGuard(CheckCancelationReason), null);

            stRecieveMoneyAndInstallModem.AddNewTransition("پول دریافت  و مودم نصب شد", stCompleteRegistrationForm, new WorkflowGuard(CheckInstallationInfo) + new WorkflowGuard(CheckMobinRequiredFields) + new WorkflowGuard(CheckUsername), null);
            stRecieveMoneyAndInstallModem.AddNewTransition("انصراف", stCancel, new WorkflowGuard(CheckCancelationReason), null);

            stCompleteRegistrationForm.AddNewTransition("تکمیل شد", stConfirmDocuments, new WorkflowGuard(CheckInstallationInfo) + new WorkflowGuard(CheckMobinRequiredFields), null);
            stCompleteRegistrationForm.AddNewTransition("انصراف", stCancel, new WorkflowGuard(CheckCancelationReason), null);

            stConfirmDocuments.AddNewTransition("مدارک تایید شد", stArchiveDocuments, new WorkflowGuard(CheckPhotos) + new WorkflowGuard(CheckInstallationInfo) + new WorkflowGuard(CheckMobinRequiredFields), null);
            stConfirmDocuments.AddNewTransition("انصراف", stCancel, new WorkflowGuard(CheckCancelationReason) + new WorkflowGuard(CheckUsername), null);

            stArchiveDocuments.AddNewTransition("آرشیو شد", stControlDocuments, new WorkflowGuard(CheckInstallationInfo) + new WorkflowGuard(CheckMobinRequiredFields), null);
            stArchiveDocuments.AddNewTransition("انصراف", stCancel, new WorkflowGuard(CheckCancelationReason) + new WorkflowGuard(CheckUsername), null);

            stControlDocuments.AddNewTransition("مدارک کنترل شد", stRegisterInSaleSoftware, new WorkflowGuard(CheckInstallationInfo) + new WorkflowGuard(CheckMobinRequiredFields), null);
            stControlDocuments.AddNewTransition("انصراف", stCancel, new WorkflowGuard(CheckCancelationReason) + new WorkflowGuard(CheckUsername), null);

            stRegisterInSaleSoftware.AddNewTransition("ثبت شد", stConfirmFinancial, new WorkflowGuard(CheckInstallationInfo) + new WorkflowGuard(CheckMobinRequiredFields), new WorkflowAction(SetRegistered));
            stRegisterInSaleSoftware.AddNewTransition("ثبت ناموفق", stRegisterFailed, null, null);
            stRegisterInSaleSoftware.AddNewTransition("انصراف", stCancel, new WorkflowGuard(CheckCancelationReason), null);

            stRegisterFailed.AddNewTransition("انصراف", stCancel, new WorkflowGuard(CheckCancelationReason), null);
            stRegisterFailed.AddNewTransition("بازگشت به ثبت نام مبین", stRegisterInSaleSoftware, null, new WorkflowAction(SetRegisteredFalse));

            stConfirmFinancial.AddNewTransition("مدارک مالی تایید شد", stActivateService, new WorkflowGuard(CheckFinancialRefNum) + new WorkflowGuard(CheckInvoiceNumber) + new WorkflowGuard(CheckUsername) + new WorkflowGuard(CheckInstallationInfo) + new WorkflowGuard(CheckMobinRequiredFields), null);
            stConfirmFinancial.AddNewTransition("انصراف", stCancel, new WorkflowGuard(CheckCancelationReason), null);

            stActivateService.AddNewTransition("سرویس فعال شد", stFinalizeActivation, null, new WorkflowAction(UpdateServiceStartDate));
            stActivateService.AddNewTransition("انصراف", stCancel, new WorkflowGuard(CheckCancelationReason), null);
            stActivateService.AddNewTransition("ثبت نام ناموفق", stRegisterFailed, null, null);
            stActivateService.AddNewTransition("فعالسازی ناموفق", stActivateServiceFailed, null, null); 

            stActivateServiceFailed.AddNewTransition("بازگشت به فعالسازی سرویس", stActivateService, null, new WorkflowAction(SetActivatedFalse));

            stFinalizeActivation.AddNewTransition("ثبت نام تکمیل شد", stInUse, null, new WorkflowAction(SetActivated));
            stFinalizeActivation.AddNewTransition("تکمیل ثبت نام ناموفق", stFinalizeActivationFailed, null, null);

            stFinalizeActivationFailed.AddNewTransition("بازگشت به تکمیل ثبت نام", stFinalizeActivation, null, new WorkflowAction(SetActivatedFalse));

            stInUse.AddNewTransition("سرویس پایان یافت", stServiceFinished);

            base.StateEngine.SetInitialState(stInitial);
            base.OnBasePersisted += new WorkflowPersisted(persistOrderWorkflow);
        }

        private void persistOrderWorkflow()
        {
            CRMRepository repo = new CRMRepository();
            Order o = repo.GetOrderById(this.ExternalId);
            o.LastUpdate = DateTime.Now;
            o.WorkflowStateId = base.StateId;
            
            if ( this.lastOperatorId.HasValue )
                o.OperatorId = this.lastOperatorId.Value;

            repo.Save();
        }

        private void UpdateServiceStartDate()
        {
            CRMRepository crmRepository = new CRMRepository();
            Order o = crmRepository.GetOrderById(this.ExternalId);
            o.ServiceStartDate = DateTime.Now;
            o.ServiceExpirationDate = o.ServiceStartDate.Value.AddMonths(o.Service.ServicePeriod.Value);
            
            crmRepository.Save();
        }

        private WorkflowGuardResult CheckUsername()
        {
            CRMRepository crmRepository = new CRMRepository();
            Order o = crmRepository.GetOrderById(this.ExternalId);

            if (String.IsNullOrEmpty(o.Contact.GetUsername()))
                return new WorkflowGuardResult("برای مودم این کاربر شناسه کاربری ثبت نشده است. لطفا اطلاعات مودم را تکمیل فرمایید.");

            return WorkflowGuardResult.Success;
        }

        private WorkflowGuardResult CheckInstallationInfo()
        {
            CRMRepository crmRepository = new CRMRepository();
            Order o = crmRepository.GetOrderById(this.ExternalId);

            if (!o.InstallationPrice.HasValue || String.IsNullOrEmpty(o.Installer))
                return new WorkflowGuardResult("پر کردن اطلاعات نصب از جمله نام نصاب و هزینه نصب برای این مرحله الزامی می باشد لطفا اطلاعات را تکمیل فرمایید");

            if (o.InstallationForm == null)
            {
                return new WorkflowGuardResult("برای تکمیل عملیات نصب آپلود کردن فرم نصب الزامی می باشد لطفا سفارش را ویرایش کرده و فرم نصب را آپلود کنید");
            }

            InstallationInformation insInfo = o.InstallationInformations.FirstOrDefault();

            if (insInfo == null)
                return new WorkflowGuardResult("لطفا از طریق ویرایش سفارش اطلاعات مربوط به آدرس نصب را تکمیل فرمایید این اطلاعات برای ثبت نام مشترک در مبین ضروری می باشد");

            if (String.IsNullOrEmpty(insInfo.Address) || String.IsNullOrEmpty(insInfo.BuildingName) ||
                 String.IsNullOrEmpty(insInfo.Floor) || String.IsNullOrEmpty(insInfo.Plaque) || String.IsNullOrEmpty(insInfo.Region) ||
                String.IsNullOrEmpty(insInfo.UnitNumber))
            {
                return new WorkflowGuardResult("لطفا از طریق ویرایش سفارش تمام اطلاعات مربوط به آدرس نصب را تکمیل فرمایید این اطلاعات برای ثبت نام مشترک در مبین ضروری می باشد");
            }
                 

            return WorkflowGuardResult.Success;
        }

        private WorkflowGuardResult CheckFinancialRefNum()
        {
            CRMRepository crmRepository = new CRMRepository();
            Order o = crmRepository.GetOrderById(this.ExternalId);

            if (String.IsNullOrEmpty(o.FinancialRefNum))
                return new WorkflowGuardResult("برای تایید مالی پر کردن فیلد شناسه واریزی / شماره کارت الزامی می باشد");

            return WorkflowGuardResult.Success;
        }

        private WorkflowGuardResult CheckPhotos()
        {
            CRMRepository crmRepository = new CRMRepository();
            Order o = crmRepository.GetOrderById(this.ExternalId);

            if (o.Contact.ContactTypeId == (int)ContactTypes.Company)
            {
                CompanyContact cc = o.Contact.CompanyContacts.FirstOrDefault();
                if (cc.ServicePhoto == null)
                    return new WorkflowGuardResult("لطفا اطلاعات مربوط به مشترک در مورد تصویر مدرک سرویس را کامل فرمایید");

                if (cc.IdPhoto == null)
                    return new WorkflowGuardResult("لطفا اطلاعات مربوط به مشترک در مورد تصویر شناسایی را تکمیل فرمایید");
            }
            else if (o.Contact.ContactTypeId == (int)ContactTypes.Personal)
            {
                PersonalContact pc = o.Contact.PersonalContacts.FirstOrDefault();

                if (pc.IdentityPhoto == null)
                    return new WorkflowGuardResult("لطفا اطلاعات مربوط به مشترک در مورد تصویر شناسایی را تکمیل فرمایید");

                if (o.Service.IsCertificateRequired && pc.ServicePhoto == null)
                {
                    return new WorkflowGuardResult("لطفا اطلاعات مربوط به مشترک در مورد تصویر سرویس را تکمیل فرمایید این سرویس برای مشترک حقیقی نیاز به مدرک شناسایی دارد");
                }
            }

            return WorkflowGuardResult.Success;
        }

        private WorkflowGuardResult CheckInvoiceNumber()
        {
            CRMRepository crmRepository = new CRMRepository();
            Order o = crmRepository.GetOrderById(this.ExternalId);

            if (String.IsNullOrEmpty(o.InvoiceNumber))
                return new WorkflowGuardResult("برای تکمیل مدارک پر کردن فیلد شماره فاکتور الزامی می باشد");

            return WorkflowGuardResult.Success;
        }

        private WorkflowGuardResult CheckCancelationReason()
        {
            CRMRepository crmRepository = new CRMRepository();
            Order o = crmRepository.GetOrderById(base.ExternalId);

            if (!o.CancelReasonId.HasValue)
                return new WorkflowGuardResult("لطفا قبل از انصراف علت انصراف را از طریق ویرایش سفارش مشخص کنید.");

            return WorkflowGuardResult.Success;
        }

        protected override void InitializeDataDictionary()
        {
        }

        public WorkflowGuardResult CheckMobinRequiredFields()
        {
            CRMRepository crmRepository = new CRMRepository();
            Order o = crmRepository.GetOrderById(base.ExternalId);

            if (String.IsNullOrEmpty(o.Service.MobinServiceName))
                return new WorkflowGuardResult("معادل نام سرویس مربوطه در مبین انتخاب نشده است لطفا با مدیر سیستم هماهنگ کنید");

            if (String.IsNullOrEmpty(o.Contact.FullContactTitle))
                return new WorkflowGuardResult("نام انگلیسی مشترک پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");

            if (String.IsNullOrEmpty(o.Contact.Email))
                return new WorkflowGuardResult("آدرس ایمیل مشترک پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");

            if(!EmailValidator.IsValidEmail(o.Contact.Email))
                return new WorkflowGuardResult("آدرس ایمیل مشترک معتبر نمی باشد لطفا از طریق ویرایش مشترک این فیلد را اصلاح کنید");

            if (o.Contact.ContactTypeId == (int)ContactTypes.Personal)
            {
                PersonalContact pc = o.Contact.PersonalContacts.FirstOrDefault();
                if (String.IsNullOrEmpty(pc.AcademicDegree))
                    return new WorkflowGuardResult("مدرک دانشگاهی مشترک پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");
                
                if ( !pc.Birthday.HasValue )
                    return new WorkflowGuardResult("تاریخ تولد مشترک پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");
                
                if ( String.IsNullOrEmpty(pc.EducationalMajor) )
                    return new WorkflowGuardResult("رشته تحصیلی مشترک پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");
                
                if (String.IsNullOrEmpty(pc.IdentityIssuePlace))
                    return new WorkflowGuardResult("محل صدور شناسنامه مشترک پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");

                if (String.IsNullOrEmpty(pc.Job))
                    return new WorkflowGuardResult("شغل مشترک پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");
            }
            else
            {
                CompanyContact cc = o.Contact.CompanyContacts.FirstOrDefault();

                if ( String.IsNullOrEmpty(cc.ManagerFirstName) )
                    return new WorkflowGuardResult("نام مدیرعامل پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");

                if ( String.IsNullOrEmpty(cc.ManagerLastName) )
                    return new WorkflowGuardResult("نام خانوادگی مدیرعامل پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");

                if ( String.IsNullOrEmpty(cc.ManagerFullNameEnglish) )
                    return new WorkflowGuardResult("نام کامل انگلیسی مدیرعامل پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");

                if ( String.IsNullOrEmpty(cc.ManagerNationalCode) )
                    return new WorkflowGuardResult("کد ملی مدیرعامل پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");

                if ( !cc.ManagerBirthday.HasValue )
                    return new WorkflowGuardResult("تاریخ تولد پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");

                if ( String.IsNullOrEmpty(cc.ManagerEducationalMajor) )
                    return new WorkflowGuardResult("رشته تحصیلی مدیرعامل پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");

                if ( String.IsNullOrEmpty(cc.ManagerAcademicDegree) )
                    return new WorkflowGuardResult("مدرک دانشگاهی مدیرعامل پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");

                if (String.IsNullOrEmpty(cc.CompanyActivityField))
                    return new WorkflowGuardResult("زمینه فعالیت شرکت پر نشده است لطفا از طریق ویرایش مشترک این فیلد را پر کنید");
            }

            return WorkflowGuardResult.Success;
        }

        private void SetRegistered()
        {
            CRMRepository crmRepository = new CRMRepository();
            Order o = crmRepository.GetOrderById(base.ExternalId);
            o.Registered = true;
            o.LastUpdate = DateTime.Now;
            if ( lastOperatorId.HasValue )
                o.OperatorId = lastOperatorId.Value;

            crmRepository.Save();
        }

        private void SetActivated()
        {
            CRMRepository crmRepository = new CRMRepository();
            Order o = crmRepository.GetOrderById(base.ExternalId);
            
            o.Activated = true;

            o.LastUpdate = DateTime.Now;
            if (lastOperatorId.HasValue)
                o.OperatorId = lastOperatorId.Value;

            crmRepository.Save();
        }

        private void SetRegisteredFalse()
        {
            CRMRepository crmRepository = new CRMRepository();
            Order o = crmRepository.GetOrderById(base.ExternalId);
            o.Registered = false;
            o.LastUpdate = DateTime.Now;

            if (lastOperatorId.HasValue)
                o.OperatorId = lastOperatorId.Value;

            crmRepository.Save();
        }

        private void SetActivatedFalse()
        {
            CRMRepository crmRepository = new CRMRepository();
            Order o = crmRepository.GetOrderById(base.ExternalId);
            o.Activated = false;
            o.LastUpdate = DateTime.Now;

            if (lastOperatorId.HasValue)
                o.OperatorId = lastOperatorId.Value;

            crmRepository.Save();
        }
    }
}
